/*!
 * \file CtaStraBaseCtx.h
 * \project	WonderTrader
 *
 * \author Wesley
 * \date 2020/03/30
 * 
 * \brief CTA策略基础上下文头文件
 * 
 * 本文件定义了CTA策略基础上下文类，是所有CTA策略上下文的基类。
 * 实现了ICtaStraCtx接口，提供CTA策略运行所需的基础功能，包括持仓管理、
 * 信号处理、数据访问、条件单管理、资金管理等核心功能。
 */
#pragma once
#include "../Includes/ICtaStraCtx.h"
#include "../Includes/FasterDefs.h"
#include "../Includes/WTSDataDef.hpp"

#include "../Share/BoostFile.hpp"
#include "../Share/fmtlib.h"

class CtaStrategy;

NS_WTP_BEGIN

class WtCtaEngine;

/**
 * @brief 条件单动作类型常量
 */
const char COND_ACTION_OL = 0;	/**< 开多 */
const char COND_ACTION_CL = 1;	/**< 平多 */
const char COND_ACTION_OS = 2;	/**< 开空 */
const char COND_ACTION_CS = 3;	/**< 平空 */
const char COND_ACTION_SP = 4;	/**< 直接设置仓位 */

/**
 * @struct _CondEntrust
 * @brief 条件委托结构体
 * 
 * 定义条件委托的各项参数，包括触发条件、委托数量、动作类型等
 */
typedef struct _CondEntrust
{
	WTSCompareField _field;		/**< 比较字段 */
	WTSCompareType	_alg;		/**< 比较算法 */
	double			_target;	/**< 目标值 */

	double			_qty;		/**< 委托数量 */

	char			_action;	/**< 动作类型：0-开多, 1-平多, 2-开空, 3-平空 */

	char			_code[MAX_INSTRUMENT_LENGTH];	/**< 合约代码 */
	char			_usertag[32];					/**< 用户标签 */

	/**
	 * @brief 构造函数
	 * 
	 * 初始化所有成员为0
	 */
	_CondEntrust()
	{
		memset(this, 0, sizeof(_CondEntrust));
	}

} CondEntrust;

typedef std::vector<CondEntrust>	CondList;			/**< 条件委托列表 */
typedef faster_hashmap<LongKey, CondList>	CondEntrustMap;	/**< 条件委托映射表 */

/**
 * @class CtaStraBaseCtx
 * @brief CTA策略基础上下文类
 * 
 * CTA策略基础上下文类，继承自ICtaStraCtx接口，为所有CTA策略提供基础功能。
 * 
 * 主要功能包括：
 * - 持仓管理：跟踪和管理策略的持仓信息
 * - 信号处理：处理策略产生的交易信号
 * - 数据访问：提供K线、Tick等市场数据访问接口
 * - 条件单管理：支持条件委托的创建和触发
 * - 资金管理：跟踪策略的盈亏和资金状况
 * - 日志记录：记录交易、平仓、资金等日志
 * - 用户数据：支持策略自定义数据的存储和读取
 * 
 * @note 这是一个基类，具体的策略上下文类需要继承此类
 * @see ICtaStraCtx, CtaStraContext, WtCtaEngine
 */
class CtaStraBaseCtx : public ICtaStraCtx
{
public:
	/**
	 * @brief 构造函数
	 * 
	 * 创建CTA策略基础上下文实例
	 * 
	 * @param engine CTA引擎指针
	 * @param name 策略名称
	 */
	CtaStraBaseCtx(WtCtaEngine* engine, const char* name);
	
	/**
	 * @brief 析构函数
	 * 
	 * 清理资源
	 */
	virtual ~CtaStraBaseCtx();

private:
	/**
	 * @brief 初始化输出文件
	 * 
	 * 创建策略运行所需的各种日志文件
	 */
	void	init_outputs();
	
	/**
	 * @brief 记录信号日志
	 * 
	 * @param stdCode 标准合约代码
	 * @param target 目标仓位
	 * @param price 信号价格
	 * @param gentime 生成时间
	 * @param usertag 用户标签
	 */
	inline void log_signal(const char* stdCode, double target, double price, uint64_t gentime, const char* usertag = "");
	
	/**
	 * @brief 记录交易日志
	 * 
	 * @param stdCode 标准合约代码
	 * @param isLong 是否多头
	 * @param isOpen 是否开仓
	 * @param curTime 当前时间
	 * @param price 成交价格
	 * @param qty 成交数量
	 * @param userTag 用户标签
	 * @param fee 手续费
	 * @param barNo K线编号
	 */
	inline void	log_trade(const char* stdCode, bool isLong, bool isOpen, uint64_t curTime, double price, double qty, const char* userTag = "", double fee = 0.0, uint32_t barNo = 0);
	
	/**
	 * @brief 记录平仓日志
	 * 
	 * @param stdCode 标准合约代码
	 * @param isLong 是否多头
	 * @param openTime 开仓时间
	 * @param openpx 开仓价格
	 * @param closeTime 平仓时间
	 * @param closepx 平仓价格
	 * @param qty 平仓数量
	 * @param profit 本次盈亏
	 * @param totalprofit 总盈亏
	 * @param enterTag 开仓标签
	 * @param exitTag 平仓标签
	 * @param openBarNo 开仓K线编号
	 * @param closeBarNo 平仓K线编号
	 */
	inline void	log_close(const char* stdCode, bool isLong, uint64_t openTime, double openpx, uint64_t closeTime, double closepx, double qty,
		double profit, double totalprofit = 0, const char* enterTag = "", const char* exitTag = "", uint32_t openBarNo = 0, uint32_t closeBarNo = 0);

	/**
	 * @brief 保存数据
	 * 
	 * @param flag 保存标志位
	 */
	void	save_data(uint32_t flag = 0xFFFFFFFF);
	
	/**
	 * @brief 加载数据
	 * 
	 * @param flag 加载标志位
	 */
	void	load_data(uint32_t flag = 0xFFFFFFFF);

	/**
	 * @brief 加载用户数据
	 */
	void	load_userdata();
	
	/**
	 * @brief 保存用户数据
	 */
	void	save_userdata();

	/**
	 * @brief 更新动态盈亏
	 * 
	 * @param stdCode 标准合约代码
	 * @param price 当前价格
	 */
	void	update_dyn_profit(const char* stdCode, double price);

	/**
	 * @brief 执行设置仓位操作
	 * 
	 * @param stdCode 标准合约代码
	 * @param qty 目标数量
	 * @param userTag 用户标签
	 * @param bTriggered 是否由条件单触发
	 */
	void	do_set_position(const char* stdCode, double qty, const char* userTag = "", bool bTriggered = false);
	
	/**
	 * @brief 追加信号
	 * 
	 * @param stdCode 标准合约代码
	 * @param qty 信号数量
	 * @param userTag 用户标签
	 */
	void	append_signal(const char* stdCode, double qty, const char* userTag = "");

	/**
	 * @brief 获取条件委托列表
	 * 
	 * @param stdCode 标准合约代码
	 * @return 条件委托列表引用
	 */
	inline CondList& get_cond_entrusts(const char* stdCode);
	
private:
	/**
	 * @brief 调试日志模板函数
	 * 
	 * @tparam Args 参数类型
	 * @param format 格式字符串
	 * @param args 参数列表
	 */
	template<typename... Args>
	void log_debug(const char* format, const Args& ...args)
	{
		std::string s = fmt::sprintf(format, args...);
		stra_log_debug(s.c_str());
	}

	/**
	 * @brief 信息日志模板函数
	 * 
	 * @tparam Args 参数类型
	 * @param format 格式字符串
	 * @param args 参数列表
	 */
	template<typename... Args>
	void log_info(const char* format, const Args& ...args)
	{
		std::string s = fmt::sprintf(format, args...);
		stra_log_info(s.c_str());
	}

	/**
	 * @brief 错误日志模板函数
	 * 
	 * @tparam Args 参数类型
	 * @param format 格式字符串
	 * @param args 参数列表
	 */
	template<typename... Args>
	void log_error(const char* format, const Args& ...args)
	{
		std::string s = fmt::sprintf(format, args...);
		stra_log_error(s.c_str());
	}

public:
	/**
	 * @brief 获取上下文ID
	 * 
	 * @return 上下文ID
	 */
	virtual uint32_t id() { return _context_id; }

	//回调函数
	/**
	 * @brief 初始化回调
	 */
	virtual void on_init() override;
	
	/**
	 * @brief 交易时段开始回调
	 * 
	 * @param uTDate 交易日期
	 */
	virtual void on_session_begin(uint32_t uTDate) override;
	
	/**
	 * @brief 交易时段结束回调
	 * 
	 * @param uTDate 交易日期
	 */
	virtual void on_session_end(uint32_t uTDate) override;
	
	/**
	 * @brief Tick数据回调
	 * 
	 * @param stdCode 标准合约代码
	 * @param newTick 新Tick数据
	 * @param bEmitStrategy 是否触发策略
	 */
	virtual void on_tick(const char* stdCode, WTSTickData* newTick, bool bEmitStrategy = true) override;
	
	/**
	 * @brief K线数据回调
	 * 
	 * @param stdCode 标准合约代码
	 * @param period K线周期
	 * @param times K线倍数
	 * @param newBar 新K线数据
	 */
	virtual void on_bar(const char* stdCode, const char* period, uint32_t times, WTSBarStruct* newBar) override;
	
	/**
	 * @brief 调度回调
	 * 
	 * @param curDate 当前日期
	 * @param curTime 当前时间
	 * @return 是否继续调度
	 */
	virtual bool on_schedule(uint32_t curDate, uint32_t curTime) override;

	/**
	 * @brief 枚举持仓回调
	 * 
	 * @param cb 回调函数
	 */
	virtual void enum_position(FuncEnumCtaPosCallBack cb) override;

	//////////////////////////////////////////////////////////////////////////
	//策略接口
	/**
	 * @brief 开多仓
	 * 
	 * @param stdCode 标准合约代码
	 * @param qty 开仓数量
	 * @param userTag 用户标签
	 * @param limitprice 限价
	 * @param stopprice 止损价
	 */
	virtual void stra_enter_long(const char* stdCode, double qty, const char* userTag = "", double limitprice = 0.0, double stopprice = 0.0) override;
	
	/**
	 * @brief 开空仓
	 * 
	 * @param stdCode 标准合约代码
	 * @param qty 开仓数量
	 * @param userTag 用户标签
	 * @param limitprice 限价
	 * @param stopprice 止损价
	 */
	virtual void stra_enter_short(const char* stdCode, double qty, const char* userTag = "", double limitprice = 0.0, double stopprice = 0.0) override;
	
	/**
	 * @brief 平多仓
	 * 
	 * @param stdCode 标准合约代码
	 * @param qty 平仓数量
	 * @param userTag 用户标签
	 * @param limitprice 限价
	 * @param stopprice 止损价
	 */
	virtual void stra_exit_long(const char* stdCode, double qty, const char* userTag = "", double limitprice = 0.0, double stopprice = 0.0) override;
	
	/**
	 * @brief 平空仓
	 * 
	 * @param stdCode 标准合约代码
	 * @param qty 平仓数量
	 * @param userTag 用户标签
	 * @param limitprice 限价
	 * @param stopprice 止损价
	 */
	virtual void stra_exit_short(const char* stdCode, double qty, const char* userTag = "", double limitprice = 0.0, double stopprice = 0.0) override;

	/**
	 * @brief 获取持仓
	 * 
	 * @param stdCode 标准合约代码
	 * @param bOnlyValid 是否只获取有效持仓
	 * @param userTag 用户标签
	 * @return 持仓数量
	 */
	virtual double stra_get_position(const char* stdCode, bool bOnlyValid = false, const char* userTag = "") override;
	
	/**
	 * @brief 设置仓位
	 * 
	 * @param stdCode 标准合约代码
	 * @param qty 目标数量
	 * @param userTag 用户标签
	 * @param limitprice 限价
	 * @param stopprice 止损价
	 */
	virtual void stra_set_position(const char* stdCode, double qty, const char* userTag = "", double limitprice = 0.0, double stopprice = 0.0) override;
	
	/**
	 * @brief 获取价格
	 * 
	 * @param stdCode 标准合约代码
	 * @return 当前价格
	 */
	virtual double stra_get_price(const char* stdCode) override;

	/**
	 * @brief 获取交易日
	 * 
	 * @return 交易日期
	 */
	virtual uint32_t stra_get_tdate() override;
	
	/**
	 * @brief 获取日期
	 * 
	 * @return 当前日期
	 */
	virtual uint32_t stra_get_date() override;
	
	/**
	 * @brief 获取时间
	 * 
	 * @return 当前时间
	 */
	virtual uint32_t stra_get_time() override;

	/**
	 * @brief 获取资金数据
	 * 
	 * @param flag 标志位
	 * @return 资金数据
	 */
	virtual double stra_get_fund_data(int flag /* = 0 */) override;

	/**
	 * @brief 获取首次进场时间
	 * 
	 * @param stdCode 标准合约代码
	 * @return 首次进场时间
	 */
	virtual uint64_t stra_get_first_entertime(const char* stdCode) override;
	
	/**
	 * @brief 获取最后进场时间
	 * 
	 * @param stdCode 标准合约代码
	 * @return 最后进场时间
	 */
	virtual uint64_t stra_get_last_entertime(const char* stdCode) override;
	
	/**
	 * @brief 获取最后出场时间
	 * 
	 * @param stdCode 标准合约代码
	 * @return 最后出场时间
	 */
	virtual uint64_t stra_get_last_exittime(const char* stdCode) override;
	
	/**
	 * @brief 获取最后进场价格
	 * 
	 * @param stdCode 标准合约代码
	 * @return 最后进场价格
	 */
	virtual double stra_get_last_enterprice(const char* stdCode) override;
	
	/**
	 * @brief 获取持仓均价
	 * 
	 * @param stdCode 标准合约代码
	 * @return 持仓均价
	 */
	virtual double stra_get_position_avgpx(const char* stdCode) override;
	
	/**
	 * @brief 获取持仓盈亏
	 * 
	 * @param stdCode 标准合约代码
	 * @return 持仓盈亏
	 */
	virtual double stra_get_position_profit(const char* stdCode) override;

	/**
	 * @brief 获取明细进场时间
	 * 
	 * @param stdCode 标准合约代码
	 * @param userTag 用户标签
	 * @return 明细进场时间
	 */
	virtual uint64_t stra_get_detail_entertime(const char* stdCode, const char* userTag) override;
	
	/**
	 * @brief 获取明细成本
	 * 
	 * @param stdCode 标准合约代码
	 * @param userTag 用户标签
	 * @return 明细成本
	 */
	virtual double stra_get_detail_cost(const char* stdCode, const char* userTag) override;
	
	/**
	 * @brief 获取明细盈亏
	 * 
	 * @param stdCode 标准合约代码
	 * @param userTag 用户标签
	 * @param flag 标志位
	 * @return 明细盈亏
	 */
	virtual double stra_get_detail_profit(const char* stdCode, const char* userTag, int flag = 0) override;

	/**
	 * @brief 获取品种信息
	 * 
	 * @param stdCode 标准合约代码
	 * @return 品种信息
	 */
	virtual WTSCommodityInfo* stra_get_comminfo(const char* stdCode) override;
	
	/**
	 * @brief 获取K线数据
	 * 
	 * @param stdCode 标准合约代码
	 * @param period K线周期
	 * @param count 数据条数
	 * @param isMain 是否主力合约
	 * @return K线数据切片
	 */
	virtual WTSKlineSlice*	stra_get_bars(const char* stdCode, const char* period, uint32_t count, bool isMain = false) override;
	
	/**
	 * @brief 获取Tick数据
	 * 
	 * @param stdCode 标准合约代码
	 * @param count 数据条数
	 * @return Tick数据切片
	 */
	virtual WTSTickSlice*	stra_get_ticks(const char* stdCode, uint32_t count) override;
	
	/**
	 * @brief 获取最新Tick
	 * 
	 * @param stdCode 标准合约代码
	 * @return 最新Tick数据
	 */
	virtual WTSTickData*	stra_get_last_tick(const char* stdCode) override;

	/**
	 * @brief 订阅Tick数据
	 * 
	 * @param stdCode 标准合约代码
	 */
	virtual void stra_sub_ticks(const char* stdCode) override;

	/**
	 * @brief 输出信息日志
	 * 
	 * @param message 日志消息
	 */
	virtual void stra_log_info(const char* message) override;
	
	/**
	 * @brief 输出调试日志
	 * 
	 * @param message 日志消息
	 */
	virtual void stra_log_debug(const char* message) override;
	
	/**
	 * @brief 输出错误日志
	 * 
	 * @param message 日志消息
	 */
	virtual void stra_log_error(const char* message) override;

	/**
	 * @brief 保存用户数据
	 * 
	 * @param key 键名
	 * @param val 键值
	 */
	virtual void stra_save_user_data(const char* key, const char* val) override;

	/**
	 * @brief 读取用户数据
	 * 
	 * @param key 键名
	 * @param defVal 默认值
	 * @return 键值
	 */
	virtual const char* stra_load_user_data(const char* key, const char* defVal = "") override;

protected:
	uint32_t		_context_id;		/**< 上下文ID */
	WtCtaEngine*	_engine;			/**< CTA引擎指针 */

	uint64_t		_total_calc_time;	/**< 总计算时间 */
	uint32_t		_emit_times;		/**< 总计算次数 */

	std::string		_main_key;			/**< 主键 */

	/**
	 * @struct _KlineTag
	 * @brief K线标记结构体
	 */
	typedef struct _KlineTag
	{
		bool			_closed;		/**< 是否已闭合 */

		_KlineTag() :_closed(false){}

	} KlineTag;
	typedef faster_hashmap<LongKey, KlineTag> KlineTags;
	KlineTags	_kline_tags;			/**< K线标记映射表 */

	typedef faster_hashmap<LongKey, double> PriceMap;
	PriceMap		_price_map;			/**< 价格映射表 */

	/**
	 * @struct _DetailInfo
	 * @brief 持仓明细信息结构体
	 */
	typedef struct _DetailInfo
	{
		bool		_long;				/**< 是否多头 */
		double		_price;				/**< 开仓价格 */
		double		_volume;			/**< 持仓数量 */
		uint64_t	_opentime;			/**< 开仓时间 */
		uint32_t	_opentdate;			/**< 开仓交易日 */
		double		_max_profit;		/**< 最大盈利 */
		double		_max_loss;			/**< 最大亏损 */
		double		_profit;			/**< 当前盈亏 */
		char		_opentag[32];		/**< 开仓标签 */
		uint32_t	_open_barno;		/**< 开仓K线编号 */

		_DetailInfo()
		{
			memset(this, 0, sizeof(_DetailInfo));
		}
	} DetailInfo;

	/**
	 * @struct _PosInfo
	 * @brief 持仓信息结构体
	 */
	typedef struct _PosInfo
	{
		double		_volume;			/**< 持仓数量 */
		double		_closeprofit;		/**< 平仓盈亏 */
		double		_dynprofit;			/**< 动态盈亏 */

		uint64_t	_last_entertime;	/**< 最后进场时间 */
		uint64_t	_last_exittime;		/**< 最后出场时间 */

		double		_frozen;			/**< 冻结数量 */
		uint32_t	_frozen_date;		/**< 冻结日期 */

		std::vector<DetailInfo> _details;	/**< 持仓明细列表 */

		_PosInfo()
		{
			_volume = 0;
			_closeprofit = 0;
			_dynprofit = 0;
			_last_entertime = 0;
			_last_exittime = 0;
			_frozen = 0;
			_frozen_date = 0;
		}
	} PosInfo;
	typedef faster_hashmap<LongKey, PosInfo> PositionMap;
	PositionMap		_pos_map;			/**< 持仓映射表 */

	/**
	 * @struct _SigInfo
	 * @brief 信号信息结构体
	 */
	typedef struct _SigInfo
	{
		double		_volume;			/**< 信号数量 */
		std::string	_usertag;			/**< 用户标签 */
		double		_sigprice;			/**< 信号价格 */
		bool		_triggered;			/**< 是否已触发 */
		uint64_t	_gentime;			/**< 生成时间 */

		_SigInfo()
		{
			_volume = 0;
			_sigprice = 0;
			_triggered = false;
			_gentime = 0;
		}
	}SigInfo;
	typedef faster_hashmap<LongKey, SigInfo>	SignalMap;
	SignalMap		_sig_map;			/**< 信号映射表 */

	BoostFilePtr	_trade_logs;		/**< 交易日志文件 */
	BoostFilePtr	_close_logs;		/**< 平仓日志文件 */
	BoostFilePtr	_fund_logs;			/**< 资金日志文件 */
	BoostFilePtr	_sig_logs;			/**< 信号日志文件 */

	CondEntrustMap	_condtions;			/**< 条件委托映射表 */
	uint64_t		_last_cond_min;		/**< 上次条件检查时间 */
	uint32_t		_last_barno;		/**< 上次处理的K线编号 */

	//是否在调度中的标记
	bool			_is_in_schedule;	/**< 是否在自动调度中 */

	//用户数据
	typedef faster_hashmap<LongKey, std::string> StringHashMap;
	StringHashMap	_user_datas;		/**< 用户数据映射表 */
	bool			_ud_modified;		/**< 用户数据是否已修改 */

	/**
	 * @struct _StraFundInfo
	 * @brief 策略资金信息结构体
	 */
	typedef struct _StraFundInfo
	{
		double	_total_profit;			/**< 总盈亏 */
		double	_total_dynprofit;		/**< 总动态盈亏 */
		double	_total_fees;			/**< 总手续费 */

		_StraFundInfo()
		{
			memset(this, 0, sizeof(_StraFundInfo));
		}
	} StraFundInfo;

	StraFundInfo		_fund_info;		/**< 策略资金信息 */

	//tick订阅列表
	faster_hashset<LongKey> _tick_subs;	/**< Tick订阅集合 */
};

NS_WTP_END